package com.hwtx.form.domain.def.meta.config;

import cn.hutool.extra.spring.SpringUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.hwtx.form.domain.FormConstants;
import com.hwtx.form.domain.def.FormConfigExt;
import com.hwtx.form.domain.def.Select;
import com.hwtx.form.domain.def.meta.Api;
import com.hwtx.form.domain.def.meta.Column;
import com.hwtx.form.domain.def.meta.Component;
import com.hwtx.form.domain.service.CommonApiInvoker;
import com.hwtx.form.domain.vo.FormConfigQueryVo;
import com.hwtx.form.domain.vo.FormData;
import com.hwtx.form.persistence.entity.ApiDef;
import com.hwtx.form.util.FormUtil;
import com.hwtx.form.util.JacksonUtil;
import io.geekidea.boot.config.properties.BootProperties;
import io.geekidea.boot.framework.exception.BusinessException;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ServerProperties;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static com.hwtx.form.domain.FormConstants.HTTP_GET;
import static com.hwtx.form.domain.service.CommonApiInvoker.getMapResult;
import static com.hwtx.form.domain.service.CommonApiInvoker.getSelectResult;
import static com.hwtx.form.util.FormUtil.getUrlContext;
import static io.geekidea.boot.generator.constant.GeneratorConstant.GET;

@Slf4j
@org.springframework.stereotype.Component
public class SelectComponentConfig implements FormComponentConfig {
    public static final String ctrSelectType = "ctrSelectType";
    public static final String dict = "dict";
    public static final String ctrSelectLink = "ctrSelectLink";
    public static final String DICT_API_CODE = "dict-info-children";

    @Resource
    private ServerProperties serverProperties;

    public static String getDict(Map<String, Object> comExt) {
        if (comExt == null) {
            return null;
        }
        return (String) comExt.get(dict);
    }

    private static FormConstants.FormComSelectType getFormComSelectType(Map<String, Object> comExt) {
        String selectType = (String) comExt.get(ctrSelectType);
        if (selectType == null) {
            throw new BusinessException("请选择字典类型");
        }
        return FormConstants.FormComSelectType.of(Integer.parseInt(selectType));
    }

    public static void buildColumnInfo(Column column, FormConfigExt.FormConfigCtr formConfigCtr) {
        Map<String, Object> comExt = formConfigCtr.getComExt();
        if (comExt == null) {
            return;
        }
        FormConstants.FormComSelectType ctrSelectType = getFormComSelectType(comExt);

        switch (ctrSelectType) {
            case FORM_COM_SELECT_DICT:
                ((Column.CommonColumn) column).setType("mapping");
                CommonApiInvoker.InvokeData invokeData = getDictContent(comExt);
                if (invokeData == null || invokeData.getRet() == null) {
                    throw new BusinessException("字典查询失败");
                }
                ((Column.CommonColumn) column).setMap(getMapResult(invokeData));
                break;
            case FORM_COM_SELECT_CUSTOM_LINK:
                HttpClient client = HttpClient.newHttpClient();
                if (comExt.get(ctrSelectLink) == null) {
                    throw new RuntimeException("请填写自定义链接");
                }
                HttpRequest request = HttpRequest.newBuilder().uri(URI.create(comExt.get(ctrSelectLink).toString())).build();
                try {
                    HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
                    if (response.statusCode() == 200) {
                        Map<String, Object> ret = JacksonUtil.json2Map(response.body());
                        if (ret != null) {
                            ((Column.CommonColumn) column).setMap(ret);
                        }
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                break;
        }
    }

    public static void buildSelectComponent(Component.Select select, FormConfigQueryVo formConfigQuery, FormConfigExt.FormConfigCtr formConfigCtr) {
        boolean isMultiple = Objects.equals(FormConstants.FormComponentType.of(formConfigCtr.getCtrType()), FormConstants.FormComponentType.FORM_COM_MUTIL_SELECT);
        Map<String, Object> comExt = formConfigCtr.getComExt();
        if (comExt == null) {
            return;
        }
        FormConstants.FormComSelectType ctrSelectType = getFormComSelectType(comExt);
        switch (ctrSelectType) {
            case FORM_COM_SELECT_DICT:
                if (comExt.get(dict) == null) {
                    throw new RuntimeException("字典不能为空");
                }
                select.setLabel(formConfigQuery.getDescription());
                CommonApiInvoker.InvokeData invokeData = getDictContent(comExt);
                if (invokeData == null || invokeData.getRet() == null) {
                    throw new BusinessException("字典查询失败");
                }
                select.setOptions(getSelectResult(invokeData));
                select.setMultiple(isMultiple);
                break;
            case FORM_COM_SELECT_CUSTOM_LINK:
                select.setMultiple(isMultiple);
                if (comExt.get(ctrSelectLink) == null) {
                    throw new RuntimeException("请填写自定义链接");
                }
                select.setSource(Api.builder().url(comExt.get(ctrSelectLink).toString()).method(HTTP_GET).build());
                break;
        }
    }

    private static CommonApiInvoker.InvokeData getDictContent(Map<String, Object> comExt) {
        ApiDef apiDef = FormUtil.getApiDef(DICT_API_CODE);
        List<String> paramInfos = CommonApiInvoker.getInputParamNames(apiDef);
        return SpringUtil.getBean(CommonApiInvoker.class).invokeApiNoCareTest(apiDef, Map.of(paramInfos.getFirst(), comExt.get(dict)));
    }

    @Override
    public Map<String, Object> getInputConfigParams(Map<String, Object> comExt, FormData formData) {
        Map<String, Object> ret = Maps.newHashMap();
        if (formData.getData().get(ctrSelectType) != null) {
            ret.put(ctrSelectType, formData.getData().get(ctrSelectType));
        }
        if (formData.getData().get(dict) != null) {
            ret.put(dict, formData.getData().get(dict));
        }
        if (formData.getData().get(ctrSelectLink) != null) {
            ret.put(ctrSelectLink, formData.getData().get(ctrSelectLink));
        }
        return ret;
    }

    @Override
    public OutputConfig getOutputConfigParams(String type, FormConfigExt.FormConfigCtr formConfigCtr) {
        if (formConfigCtr == null) {
            return null;
        }
        Map<String, Object> comExt = formConfigCtr.getComExt();
        Map<String, Object> ret = Maps.newHashMap();
        if (comExt != null) {
            ret.put(ctrSelectType, comExt.get(ctrSelectType));
            ret.put(dict, comExt.get(dict));
            ret.put(ctrSelectLink, comExt.get(ctrSelectLink));
        }
        return OutputConfig.builder().params(ret).notIncludeKeys(List.of("comExt")).build();
    }

    @Override
    public String getConfig(String type, Map<String, Object> formData) {
        BootProperties bootProperties = SpringUtil.getBean(BootProperties.class);
        String contextPath = getUrlContext(serverProperties);
        List<Component> controllers = Lists.newArrayList();
        Component.Select select = new Component.Select();
        select.setName(ctrSelectType);
        select.setId(ctrSelectType);
        select.setLabel("#i18n{controller.select.value.type}");
        select.setFormBatProp();
        select.setOptions(List.of(new Select.Option("#i18n{dict}", "1"), new Select.Option("#i18n{custom.link}", "3")));
        controllers.add(select);
        select = new Component.Select();
        select.setName(dict);
        select.setLabel("#i18n{dict.code}");
        select.setFormBatProp();
        select.setVisibleOn("this." + ctrSelectType + "==1 && this.ctrType==6");
        select.setSearchable(true);
        select.setRequired(true);
        select.setClearable(true);
        select.setSource(Api.builder().method(GET).url(bootProperties.getDomain() + contextPath + FormConstants.COMMON_URL + "/api/" + DICT_API_CODE + "/2").build());
        controllers.add(select);
        select = new Component.Select();
        select.setName(ctrSelectLink);
        select.setLabel("#i18n{url}");
        select.setFormBatProp();
        select.setVisibleOn("this." + ctrSelectType + "==3 && this.ctrType==6");
        controllers.add(select);
        return JacksonUtil.object2json(controllers);
    }
}
